package java_thinking.unit_21.concurrentutil;

/**
 * @Desc:   线程池 ThreadPoolExecutor注释.txt 主要见xmind并发思维导图
 *      1.execute(Runnable command) 执行流程见visio-线程池：
 *          1、如果线程池当前线程数量少于corePoolSize，则addWorker(command, true)创建新worker线程，如创建成功返回，如没创建
 *             成功，则执行后续步骤；
 *              addWorker(command, true)失败的原因可能是：
 *              A、线程池已经shutdown，shutdown的线程池不再接收新任务
 *              B、workerCountOf(c) < corePoolSize 判断后，由于并发，别的线程先创建了worker线程，导致workerCount>=corePoolSize
 *          2、如果线程池还在running状态，将task加入workQueue阻塞队列中，如果加入成功，进行double-check，如果加入失败
 *             （可能是队列已满），则执行后续步骤；
 *              double-check主要目的是判断刚加入workQueue阻塞队列的task是否能被执行
 *              A、如果线程池已经不是running状态了，应该拒绝添加新任务，从workQueue中删除任务
 *              B、如果线程池是运行状态，或者从workQueue中删除任务失败（刚好有一个线程执行完毕，并消耗了这个任务），确保还有
 *                 线程执行任务（只要有一个就够了）
 *      2.addWorker(Runnable firstTask, boolean core)
 *          参数：
 *              firstTask：    worker线程的初始任务，可以为空
 *              core：           true：将corePoolSize作为上限，false：将maximumPoolSize作为上限
 *          addWorker方法有4种传参的方式：
 *
 *              1、addWorker(command, true)
 *
 *              2、addWorker(command, false)
 *
 *              3、addWorker(null, false)
 *
 *              4、addWorker(null, true)
 *
 *          在execute方法中就使用了前3种，结合这个核心方法进行以下分析
 *              第一个：线程数小于corePoolSize时，放一个需要处理的task进Workers Set。如果Workers Set长度超过corePoolSize，
 *                      就返回false
 *              第二个：当队列被放满时，就尝试将这个新来的task直接放入Workers Set，而此时Workers Set的长度限制是
 *                      maximumPoolSize。如果线程池也满了的话就返回false
 *              第三个：放入一个空的task进workers Set，长度限制是maximumPoolSize。这样一个task为空的worker在线程执行的时候
 *                      会去任务队列里拿任务，这样就相当于创建了一个新的线程，只是没有马上分配任务
 *              第四个：这个方法就是放一个null的task进Workers Set，而且是在小于corePoolSize时，如果此时Set中的数量已经达到
 *                      corePoolSize那就返回false，什么也不干。实际使用中是在prestartAllCoreThreads()方法，这个方法用来为
 *                      线程池预先启动corePoolSize个worker等待从workQueue中获取任务执行
 *          执行流程：
 *          1、判断线程池当前是否为可以添加worker线程的状态，可以则继续下一步，不可以return false：
 *              A、线程池状态>shutdown，可能为stop、tidying、terminated，不能添加worker线程
 *              B、线程池状态==shutdown，firstTask不为空，不能添加worker线程，因为shutdown状态的线程池不接收新任务
 *              C、线程池状态==shutdown，firstTask==null，workQueue为空，不能添加worker线程，因为firstTask为空是为了添加一
 *                 个没有任务的线程再从workQueue获取task，而workQueue为空，说明添加无任务线程已经没有意义
 *          2、线程池当前线程数量是否超过上限（corePoolSize 或 maximumPoolSize），超过了return false，没超过则对
 *             workerCount+1，继续下一步
 *          3、在线程池的ReentrantLock保证下，向Workers Set中添加新创建的worker实例，添加完成后解锁，并启动worker线程，如果
 *             这一切都成功了，return true，如果添加worker入Set失败或启动失败，调用addWorkerFailed()逻辑
 *
 *      3.Worker类
 *        解释 Worker 类 https://www.jianshu.com/p/444d8a40ab35
 *        Worker类本身既实现了Runnable，又继承了AbstractQueuedSynchronizer（以下简称AQS），所以其既是一个可执行的任务，又可
 *        以达到锁的效果
 *        new Worker()流程：
 *        1、将AQS的state置为-1，在runWoker()前不允许中断
 *        2、待执行的任务会以参数传入，并赋予firstTask
 *        3、用Worker这个Runnable创建Thread
 *
 *
 *        可以将worker划分为：
 *        1、空闲worker：正在从workQueue阻塞队列中获取任务的worker
 *        2、运行中worker：正在task.run()执行任务的worker
 *
 *        之所以Worker自己实现Runnable，并创建Thread，在firstTask外包一层，是因为要通过Worker控制中断，而firstTask这个工作
 *        任务只是负责执行业务
 *        Worker控制中断主要有以下几方面：
 *          1、初始AQS状态为-1，此时不允许中断interrupt()，只有在worker线程启动了，执行了runWoker()，将state置为0，才能中断
 *              不允许中断体现在：
 *              A、shutdown()线程池时，会对每个worker tryLock()上锁，而Worker类这个AQS的tryAcquire()方法是固定将state从0->1，
 *                 故初始状态state==-1时tryLock()失败，没发interrupt()
 *              B、shutdownNow()线程池时，不用tryLock()上锁，但调用worker.interruptIfStarted()终止worker，interruptIfStarted()
 *                 也有state>0才能interrupt的逻辑
 *          2、为了防止某种情况下，在运行中的worker被中断，runWorker()每次运行任务时都会lock()上锁，而shutdown()这类可能会终止
 *           worker的操作需要先获取worker的锁，这样就防止了中断正在运行的线程
 *          3、控制worker内部线程中断核心代码：
 *              if (worker.tryLock()) {
 *                  Thread t = worker.thread;
 *                  t.interrupt();
 *              }
 *          4、在runWorker进入后用户任务执行之前，做了释放锁的操作，将state的从-1值改为了0，也就是说runWorker锁保护块代码之前可以被中断
 *
 *        Worker实现的AQS为不可重入锁，为了是在获得worker锁的情况下再进入其它一些需要加锁的方法，不可重入锁目的是在
 *          if (!t.isInterrupted() && w.tryLock()) 时，如果是A线程持有时，又重入了那么w.tryLock()就为true了，紧接着会把自己中断
 *          另外如果worker是可重入的锁，那么就可以中断正在运行的worker线程，这和shutdown本身所要实现的作用相违背了。
 *
 *        Worker和Task的区别：
 *        Worker是线程池中的线程，而Task虽然是runnable，但是并没有真正执行，只是被Worker调用了run方法，后面会看到这部分的实现。
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 * @authr: cww
 * @DateTime: 2019/8/1 20:57
 */

public class ThreadPoolExecutiorTheory {
}
